import serial.tools.list_ports
import time
import json
import re
'''
获取当前识别的AT口列表
输出：list:at_ports、dl_ports
'''
def at_ser_identify():
    ports = serial.tools.list_ports.comports()   # 获取所有可用的串口
    serial_numbers = [port.device for port in ports]  #获取识别到的端口号（com1)
    serial_names = [port.description for port in ports]  #获取识别到的端口号在设备管理器中的名字（USB 串行设备 (COM72)）
    
    at_ports = [serial_numbers[i] for i, name in enumerate(serial_names) if "AT" in name]
    return at_ports

'''
获取当前识别的DL口列表
输出：list:at_ports、dl_ports
'''
def dl_ser_identify():
    ports = serial.tools.list_ports.comports()   # 获取所有可用的串口
    serial_numbers = [port.device for port in ports]  #获取识别到的端口号（com1)
    serial_names = [port.description for port in ports]  #获取识别到的端口号在设备管理器中的名字（USB 串行设备 (COM72)）
    
    dl_ports = [serial_numbers[i] for i, name in enumerate(serial_names) if "DL" in name]
    return dl_ports

'''
打开at_port，发送at_commands中的AT，接收响应保存至at_responses
输入：str:at_port、list:at_commands
输出：list:at_responses
'''
def serial_at_rw(at_port, baudrate, timeout, at_commands):
    try:
        with serial.Serial(at_port, baudrate=baudrate, timeout=timeout) as ser:
            at_responses = {}
            for at in at_commands:
                at_tx = at + '\r\n'
                ser.write(at_tx.encode())
                at_rx = ser.readlines()
                at_responses[at] = [line.decode().strip() for line in at_rx]
    except serial.SerialException as e:
        print(f"无法打开端口 {at_port}: {e}")
    return at_responses

'''
在创建设备后将服务器参数更新通过串口发送至模组
模组侧收到后按照servertype分别保存至控制链路和业务链路的配置文件中，重启后连接服务器
暂定向串口发送的数据格式为：
msg = {
        "servertype":"control",
        "hostname": "mqtt.ctwing.cn",
        "port": 1883,
        "clientid":"1716701712345678",
        "username": "liuyuye",
        "password": "WdGi3iu7xoEanpYVX7uocBcTvb8-lSkkQO0QOBf1lJA"
        }
'''
def mqServerSend(servercfg, at_port, baudrate, timeout):
    msg_str = json.dumps(servercfg)
    try:
        with serial.Serial(at_port, baudrate=baudrate, timeout=timeout) as ser:
            ser.write(msg_str.encode('utf-8'))
            time.sleep(1)
            response = ser.read_all().decode('utf-8')
            ser.close()
            return response
        
    except serial.SerialException as e:
        print(f"串口通信错误 {at_port}: {e}")
        return None

def cereg_sta_check(at_port,baudrate,timeout):
    at_res = serial_at_rw(at_port,baudrate,timeout,['AT+CEREG?'])
    res_list = at_res.get('AT+CEREG?', [])
    pattern = re.compile(r'\+CEREG: \d+,1|\+CEREG: \d+,5')
    for line in res_list:
        if pattern.search(line):
            return True
    return False

def get_imei(at_port,baudrate,timeout):
    at_res = serial_at_rw(at_port,baudrate,timeout,['AT+CGSN=1'])
    res_list = at_res.get('AT+CGSN=1', [])
    if res_list[-1] == 'OK':
        imei = res_list[1]
        return imei
    return ''

def get_iccid(at_port,baudrate,timeout):
    at_res = serial_at_rw(at_port,baudrate,timeout,['AT+MCCID?'])
    res_list = at_res.get('AT+MCCID?', [])
    for line in res_list:
        match = re.search(r'\+MCCID: (\d+)', line)
        if match:
            iccid = match.group(1)
            return iccid
    return ''

def get_imsi(at_port,baudrate,timeout):
    at_res = serial_at_rw(at_port,baudrate,timeout,['AT+CIMI'])
    res_list = at_res.get('AT+CIMI', [])
    if res_list[-1] == 'OK':
        imsi = res_list[1]
        return imsi
    else:
        return ''
    
def get_csq(at_port, baudrate, timeout):
    at_res = serial_at_rw(at_port, baudrate, timeout, ['AT+CSQ'])
    res_list = at_res.get('AT+CSQ', [])
    if res_list and res_list[-1] == 'OK':
        csq_line = [line for line in res_list if line.startswith('+CSQ:')][0]
        match = re.match(r'\+CSQ:\s*(\d+),(\d+)', csq_line)
        if match:
            rssi = match.group(1)
            ber = match.group(2)
            return rssi, ber    #csq = f"RSSI: {rssi}, BER: {ber}"
    return ''
    


'''
AT指令测试
输入：str:at_port、list:at_commands
输出：list:at_test_results(pass/fail)、bool:net_status
'''
def at_test(at_port,at_commands,baudrate,timeout):
    at_res = serial_at_rw(at_port,baudrate,timeout,at_commands)
    at_result_dict = {}
    for key, response in at_res.items():
        if 'OK' in response:
            at_result_dict[key] = "pass"
        else:
            at_result_dict[key] = "fail"
    result = all(result == 'pass' for result in at_result_dict.values())
    return at_result_dict, result

if __name__ == '__main__':
    msg = {
        "servertype":"control",
        "hostname": "mqtt.ctwing.cn",
        "port": 1883,
        "clientid":"1716701712345678",
        "username": "liuyuye",
        "password": "WdGi3iu7xoEanpYVX7uocBcTvb8-lSkkQO0QOBf1lJA"
        }
    at_ports = at_ser_identify()
    dl_ports = dl_ser_identify()
    print("AT口：{}\n下载口：{}".format(at_ports,dl_ports))
    at_commands = ['ATI','AT+CGSN=1','AT+CEREG?','AT+QCCID?']
    for at_port in at_ports:
        imsi = get_imsi(at_port,115200,0.5)
        print(imsi)
        iccid = get_iccid(at_port,115200,0.5)
        print(iccid)
        csq = get_csq(at_port,115200,0.5)
        print(csq)
        imei = get_imei(at_port,115200,0.5)
        print(imei)
        print(at_port)
        at_res = serial_at_rw(at_port,115200, 0.5, at_commands)
        
        at_rst, rst = at_test(at_port,at_commands,115200,0.5)
        print(at_rst,rst)
        net_sta = cereg_sta_check(at_port,115200,0.5)
        print(net_sta)
        msg_res = mqServerSend(msg,at_port,115200,0.5)
        
        print(msg_res,type(msg_res))
        print(at_commands, at_res, at_rst,net_sta,msg_res)
